package net.chromedpork.scraper;



import net.chromedpork.hypertext.client.Client;
import net.chromedpork.hypertext.client.ClientFactory;
import net.chromedpork.hypertext.filtration.Filter;
import net.chromedpork.hypertext.filtration.FilterFactory;
import net.chromedpork.hypertext.sanitization.Cleaner;
import net.chromedpork.hypertext.validation.Assertion;

import net.chromedpork.scraper.configuration.Configuration;
import net.chromedpork.scraper.configuration.ConfigurationFactory;



/**
 *
 *  Scraper object.
 * 
 *  @author Inode <inode@chromedpork.net>
 *
 */

public class Scraper
{
    private final Configuration config;
    private final String[]      arguments;



    /**
     *
     *  Constructs a scraper object defined by an XML configuration document.
     *
     *  @param config   Filename of a XML document that defines the HTTP
     *                  request and result filter.
     * 
     *  @throws ScraperException
     *
     */

    Scraper(String config) throws ScraperException
    {
        Assertion.notNull(config, "configuration filename is null");

        try
        {
            this.config = ConfigurationFactory.getConfig(config);
        }

        catch (Exception exception)
        {
            throw new ScraperException(exception.getMessage());
        }

        this.arguments = null;
    }

    

    /**
     *
     *  Constructs a scraper object defined by an XML configuration document,
     *  and respective configuration arguments.
     *
     *  @param config       XML document that defines the HTTP request
     *                      and result filter.
     *  @param arguments    array of configuration argument strings.
     * 
     *  @throws ScraperException
     *
     */

    Scraper(String config, String... arguments) throws ScraperException
    {
        Assertion.notNull(config, "configuration file is null");
        Assertion.notNull(arguments, "arguments array is null");
        Assertion.notNegativeNorZero(arguments.length, "argument count <= 0");

        try
        {
            this.config = ConfigurationFactory.getConfig(config, arguments);
        }

        catch (Exception exception)
        {
            throw new ScraperException(exception.getMessage());
        }

        this.arguments = arguments;
    }



    /**
     *
     *  Generates an HTTP request defined in the XML configuration and
     *  scrapes the response's payload data according to the filtration
     *  strategy also included in the configuration.
     *
     *  @return results in List or Map format, depending on filter type
     *          defined in the configuration.
     *
     *  @throws ScraperException
     *
     */

    public Object scrape() throws ScraperException
    {
        Filter filter = null;
        

        if (config.getFilterType().matches("map") == true)
        {
            if (config.getExpressionReturn() != null)
            {
                filter = FilterFactory.getMapFilter(config.getExpressionKey(),
                                                    config.getExpressionValue(),
                                                    config.getExpressionReturn());
            }

            else
            {
                filter = FilterFactory.getMapFilter(config.getExpressionKey(),
                                                    config.getExpressionValue());
            }
        }

        else if (config.getFilterType().matches("list") == true)
        {
            if (config.getExpressionReturn() != null)
            {
                filter = FilterFactory.getListFilter(config.getExpressionValue(),
                                                     config.getExpressionReturn());
            }
            
            else
            {
                filter = FilterFactory.getListFilter(config.getExpressionValue());
            }
        }

        else
        {
            throw new ScraperException("Invalid filter type");
        }


        try
        {
            Client client = ClientFactory.getClient(config.getRequestMethod(),
                                                    config.getRequestURL(),
                                                    config.getHeaders(),
                                                    config.getDataString());

            return (filter.parse(Cleaner.cleanHTML(client.getResponsePayload())));
        }

        catch (Exception exception)
        {
            throw new ScraperException(exception.getMessage());
        }
    }
}
